#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/1/11 12:08
# @Author : 闫峰
# @File    : execute_strategy.py
import decimal
from decimal import Decimal
import requests
import os
import time
from common.setting import ensure_path_sep
from utils.logging_tool.log_control import LogHandler
from utils.mysqlUtils.db_pool import Database
from utils.mysqlUtils.mongodb_utils import MongoDBLink

current_path = os.path.abspath(__file__)
current_dir = os.path.dirname(current_path)
path_list = current_path.split("\\")
dis_path = "\\".join(path_list[-2:-1])


def remove_file(info_path):
    if os.path.exists(info_path):
        os.remove(info_path)
    else:
        print(f"{info_path} 不存在")


info_path = ensure_path_sep(f"\\logs\\info-{dis_path}{time.time()}")
error_path = ensure_path_sep(f"\\logs\\\error-{dis_path}{time.time()}.log")
warning_path = ensure_path_sep(f"\\logs\\warning-{dis_path}{time.time()}.log")
remove_file(info_path)
remove_file(error_path)
remove_file(warning_path)
INFO = LogHandler(info_path, level='info')
ERROR = LogHandler(error_path, level='error')
WARNING = LogHandler(warning_path, level='warning')


class ExecuteStrategy:
    env = "test_"
    zhcxkj_center_strategy_comprehensive_db = Database(ensure_path_sep("\\config\\shopeev2_config.yaml.bak"),
                                                       "test_jdw_database")
    # 定义mongodb
    t_sku_strategy_relation_modb = MongoDBLink(
        uri='mongodb://admin:Zhcx?2021@10.158.158.29:27017/?authSource=admin',
        dbname='test_zhcxkj_java_center', coll_name='t_sku_strategy_relation')

    def __init__(self, strategy_id, source_id):
        get_t_strategy_allegro = """\
             SELECT 
             b.rule_code,
             b.execute_type,
             b.filter_val,
             b.filter_min_val,
             b.filter_max_val,
             b.filter_express,
             a.strategy_type
     FROM test_zhcxkj_center_strategy_comprehensive.t_strategy_allegro a
     left join test_zhcxkj_center_strategy_comprehensive.t_strategy_rule_allegro b on a.id = b.strategy_id
    WHERE a.id = %s
    and  a.status= 1
        """

        t_strategy_allegro = self.zhcxkj_center_strategy_comprehensive_db.fetch_all_tuple(get_t_strategy_allegro,
                                                                                          (strategy_id,))
        self.source_id = source_id
        self.strategy_id = strategy_id
        self.product_model = None
        self.listing_model = None
        self.strategy_type = t_strategy_allegro[0][6]
        if not len(t_strategy_allegro):
            raise Exception("策略状态是禁用")
        for i in t_strategy_allegro:
            if i[0] == 'product_model':
                self.product_model = int(i[2])
            elif i[0] == 'listing_model':
                self.listing_model = int(i[2])
            elif i[0] == 'delivery_rules' and i[1] == 0:
                self.listing_model = int(i[1])
        print()

    def execute_strategy(self):
        # able_category_id_list = self.get_category_id_list(self.source_id)
        t_allegro_listing_template_detail = f"t_allegro_listing_template_detail_{self.listing_model}"
        t_allegro_listing_template_detail_modb = MongoDBLink(
            uri='mongodb://admin:Zhcx?2021@10.158.158.29:27017/?authSource=admin',
            dbname='zhcxkj_comprehensive_allegro', coll_name=t_allegro_listing_template_detail)
        # 获取最小的ObjectId
        filters_ObjectId_min = {
            "$and": [
                {"listingTemplateId": self.listing_model},
                {"sourceId": self.source_id}
            ]
        }
        projection1 = {"_id": 1, "sku": 1, "offerId": 1,"sourceSku":1}
        res_id_index = t_allegro_listing_template_detail_modb.select_skip_projection_limit(filters_ObjectId_min,
                                                                                           projection1, "_id", 1)
        if not res_id_index:
            return
        first_data = res_id_index
        _id_index = res_id_index[0]['_id']
        listing_set = set()
        while True:
            filters_ObjectId = {
                "$and": [
                    {"listingTemplateId": self.listing_model},
                    {"sourceId": self.source_id},
                    {"_id": {"$gt": _id_index}}
                ]
            }
            field_ = {"_id": 1, "sku": 1, "offerId": 1,"sourceSku":1}
            actual_sku_list = t_allegro_listing_template_detail_modb.select_skip_projection_limit(filters_ObjectId,
                                                                                                  field_, "_id",
                                                                                                  100)
            if first_data:
                actual_sku_list.insert(0, first_data[0])
                first_data.clear()
            if not len(actual_sku_list):
                break
            _id_index = actual_sku_list[-1].get('_id')
            # TODO
            # 模版结果表中存在sku没有的数据 14979366344
            actual_sku_list = list(filter(lambda x: x.get('sku', None) != None, actual_sku_list))

            sku_list_map = list(map(lambda x: x['sku'], actual_sku_list))

            # 取交集
            filters_ObjectId_exist = {
                "$and": [
                    {"strategy_relation.strategy_id": self.product_model},
                    {"sku": {"$in": sku_list_map}}
                ]
            }
            filters_ObjectId_exist_projection = {"sku": 1}
            actual_sku_list_filter = self.t_sku_strategy_relation_modb.select(filters_ObjectId_exist,
                                                                              filters_ObjectId_exist_projection)
            exist_sku_set = set(map(lambda x: x['sku'], actual_sku_list_filter))
            actual_sku_set_map = list(filter(lambda x: x.get('sku') in exist_sku_set, actual_sku_list))
            actual_sku_set_map = set(map(lambda x: (x['offerId'],x['sku'],x['sourceSku']), actual_sku_set_map))
            listing_set |= actual_sku_set_map

        # 否定策略过滤
        res_get_negative_source_sku_list, res_get_negative_plate_id_list, res_get_negative_sku_list = self.get_negative_sku()
        listing_set = set(filter(lambda x:x[0] not in res_get_negative_plate_id_list,listing_set))
        listing_set = set(filter(lambda x:x[1] not in res_get_negative_sku_list,listing_set))
        listing_set = set(filter(lambda x:x[2] not in res_get_negative_source_sku_list,listing_set))

        # 得到一个sku_set
        self.check_sku(self.strategy_id, listing_set)



    def get_negative_sku(self):
        get_negative_strategy = f"""
            SELECT
                a.id
            FROM
                test_zhcxkj_center_strategy_comprehensive.t_strategy_allegro a
                LEFT JOIN test_zhcxkj_center_strategy_comprehensive.t_strategy_rule_allegro b ON a.id = b.strategy_id 
            WHERE
                b.rule_code = 'negation_scope'
                AND b.filter_val =%s
                AND a.STATUS = 1
                    """
        #查询该策略类型下的所有否定策略id
        res_negative_strategy_id_tuple=self.zhcxkj_center_strategy_comprehensive_db.fetch_all_tuple(get_negative_strategy,(self.strategy_type,))

        get_negative_strategy_sku = f"""
            SELECT
            -- 	a.import_id,
            -- 	b.strategy_id,
                b.source_id,
                a.rule_code,
                a.import_val 
            FROM
                `test_zhcxkj_center_strategy_comprehensive`.`t_strategy_import_filter_allegro` a
                LEFT JOIN `test_zhcxkj_center_strategy_comprehensive`.`t_strategy_source_allegro` b ON a.import_id = b.strategy_id 
            WHERE
                a.import_id in %s
                    """
        # filter_val '策略 1创建促销 2修改促销 3删除促销 4下架 5调价 6刊登 7否定 8发货天数',
        # import_id 策略ID
        # rule_code  # '数据对象 1:渠道sku 2:平台id 3:系统sku',
        res_get_negative_strategy_sku = self.zhcxkj_center_strategy_comprehensive_db.fetch_all_tuple(get_negative_strategy_sku,(set(map(lambda x : x[0],res_negative_strategy_id_tuple)),))

        res_get_negative_source_sku = set(filter(lambda x: x[1] == '1' and (x[0]==self.source_id or x[0]== None), res_get_negative_strategy_sku))
        res_get_negative_plate_id = set(filter(lambda x: x[1] == '2' and (x[0]==self.source_id or x[0]== None), res_get_negative_strategy_sku))
        res_get_negative_sku = set(filter(lambda x: x[1] == '3' and (x[0]==self.source_id or x[0]== None), res_get_negative_strategy_sku))
        res_get_negative_source_sku_list = list(map(lambda x: x[2], res_get_negative_source_sku))
        res_get_negative_plate_id_list = list(map(lambda x: x[2], res_get_negative_plate_id))
        res_get_negative_sku_list = list(map(lambda x: x[2], res_get_negative_sku))
        return res_get_negative_source_sku_list,res_get_negative_plate_id_list,res_get_negative_sku_list


    def check_sku(self, strategy_id, sku_set):
        check_sql = f"""
        SELECT b.offer_id FROM test_zhcxkj_center_strategy_comprehensive.t_strategy_queue_allegro a
LEFT JOIN test_zhcxkj_center_strategy_comprehensive.t_operate_detail_allegro b on a.id=b.queue_id
WHERE a.strategy_id= %s
        """
        actual_sku_list = self.zhcxkj_center_strategy_comprehensive_db.fetch_all_tuple(check_sql, (strategy_id,))
        if not len(actual_sku_list):
            actual_sku_set = set()
        actual_sku_set = set(map(lambda x: x[0], actual_sku_list))
        if sku_set != actual_sku_set:
            lack = sku_set - actual_sku_set
            more = actual_sku_set - sku_set
            print()

    def category_filter(self, sku_set, source_id, able_category_id_list):

        get_sku_category = f"""
        SELECT sku,other_node_id FROM test_zhcxkj_center_category.t_sku_category WHERE platform_type=67 and 	sku in %s
        """
        sku_category = self.db.fetch_all_tuple(get_sku_category, (sku_set,))
        sku_category = tuple(map(lambda x: (x[0], int(x[1])), sku_category))
        filter_sku_set = set(filter(lambda x: x[1] in able_category_id_list, sku_category))
        filter_sku_set = set(map(lambda x: x[0], filter_sku_set))
        return filter_sku_set

    def get_category_id_list(self, source_id):
        get_category_id_list = f"""
        select t.category_id from test_zhcxkj_center_strategy_comprehensive.t_allegro_publish_source_category t 
        where t.source_id = %s
        """
        category_id_list = self.zhcxkj_center_strategy_comprehensive_db.fetch_all_tuple(get_category_id_list, (source_id,))
        if not len(category_id_list):
            return []
        return list(map(lambda x: x[0], category_id_list))

    def init_strategy(self, strategy_id, source_id):
        get_t_allegro_marketing_strategy = """
                			 SELECT status,sku_template_id,listing_template_id,strategy_type
        			 FROM test_zhcxkj_center_strategy_comprehensive.t_allegro_marketing_strategy a
        			WHERE a.id = %s
                """
        t_allegro_marketing_strategy = self.db.fetch_all_tuple(get_t_allegro_marketing_strategy, (strategy_id,))
        status = t_allegro_marketing_strategy[0][0]
        if status == 0:
            raise Exception("策略状态是禁用")
        strategy_id = strategy_id
        source_id = source_id
        sku_template_id = t_allegro_marketing_strategy[0][1]
        listing_template_id = t_allegro_marketing_strategy[0][2]
        strategy_type = t_allegro_marketing_strategy[0][3]
        return source_id, sku_template_id, listing_template_id, strategy_type

    def check_actual_offer_id_set(self, expect_offer_id_set):
        t_allegro_listing_template_detail = MongoDBLink(
            uri='mongodb://admin:Zhcx?2021@10.158.158.29:27017/?authSource=admin',
            dbname='test_zhcxkj_java_center', coll_name="t_allegro_strategy_adjust_price_detail")
        filter_sql = {"sourceId": self.source_id, "strategyId": self.strategy_id}
        field_ = {"offerId": 1}
        res = t_allegro_listing_template_detail.select(filter_sql, field_)
        actual_offer_id_set = set(map(lambda x: x['offerId'], res))
        if expect_offer_id_set != actual_offer_id_set:
            print()

    def getCalculationGrossProfitMarginViewModelList(self, calculationFormulaId, orderSourceId, listing_id_list):
        request_json = {
            "input": [

            ]
        }
        for lising in listing_id_list:
            sku_model = {
                "businessTypeCode": "AllegroLocalWarehouse",
                "calculationFormulaId": calculationFormulaId,
                "country": "PL",
                "customerId": 1,
                "orderSourceId": orderSourceId,
                "platformId": 67,
                "price": str(lising[2]),
                "sku": lising[3],
                "warehouseId": 5312,
                "warehouseTypeId": 1
            }
            request_json['input'].append(sku_model)
        request_headers = {
            "Authorization": "Basic aXJvYm90Ym94OmkxcjVvOEJvdGJveA=="
        }
        res = requests.post(
            url="http://priceapi.zhcxkj.com/api/calculationFormula/calculationPrice/getCalculationGrossProfitMarginViewModelList",
            headers=request_headers,
            json=request_json)
        sku_GrossProfitMargin_map = {}
        for data in res.json()['data']:
            sku_GrossProfitMargin_map[data["Sku"] + "@" + '{:.2f}'.format(data["Price"])] = str(
                data['GrossProfitMargin'])
        return sku_GrossProfitMargin_map

    def get_price(self, calculationFormulaId, orderSourceId, sku):
        request_json = {
            "input": {
                "businessTypeCode": "AllegroLocalWarehouse",
                "country": "PL",
                "PlatformId": 67,
                "customerId": 1,
                "orderSourceId": orderSourceId,
                "platformId": 1,
                "skuList": [
                    sku
                ],
                "warehouseId": 5312,
                "warehouseTypeId": 1,
                "CalculationFormulaId": calculationFormulaId
            }
        }
        request_headers = {
            "Authorization": "Basic aXJvYm90Ym94OmkxcjVvOEJvdGJveA=="
        }
        res = requests.post(
            url="http://priceapi.zhcxkj.com/api/CalculationFormula/CalculationPrice/GetCalculatorPriceViewModelList",
            headers=request_headers,
            json=request_json)
        if res.status_code == 200:
            return Decimal(str(res.json()['data'][0]['Price']))

    def filter_adjust_model(self, current_offer_id_set):
        # 还原

        get_data_set = f"""
                SELECT offer_id,price,sku
        FROM `test_zhcxkj_center_listing_comprehensive`.`t_allegro_listing_{self.num}` 
        WHERE offer_id in %s
        """
        listing_id_list = self.db.fetch_all_tuple(get_data_set, (current_offer_id_set,))
        filter_listing_id_list = None
        # 最终售价
        if self.price_adjust_plan == 1:
            filter_listing_id_list = self.handlerFinalsellingprice(listing_id_list)
        # 计算器公式
        elif self.price_adjust_plan == 2:
            filter_listing_id_list = self.handlerCalculatorFormulas(listing_id_list)

        return set(map(lambda x: x[0], filter_listing_id_list))

    def handlerFinalsellingprice(self, listing_id_list):
        """
        调价方案： 最终售价
        根据最终售价算法，得到调整后的价格
        1 如果类型是价格区间
            验证 调整后的价格 在  原始价格*self.min_price ——  原始价格*self.max_price之间
        2 如果是利润区间
            调研计算器得到每一条数据的利润率  验证利润率 是否在 self.min_profit—— self.max_profit 之间
        :param listing_id_list:
        :return:
        """
        filter_listing_id_list = None
        listing_id_list_map = None
        # 将 listing_id_list -> offer_id,price,adjust_price,sku
        if self.sell_price_type == 1:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] * (100 - self.price_percentage) / 100, x[2]),
                    listing_id_list))
        elif self.sell_price_type == 2:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] * (100 + self.price_percentage) / 100, x[2]),
                    listing_id_list))
        elif self.sell_price_type == 3:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] - self.price_percentage, x[2]), listing_id_list))
        elif self.sell_price_type == 4:
            listing_id_list_map = list(
                map(lambda x: (x[0], x[1], x[1] + self.price_percentage, x[2]), listing_id_list))
        # offer_id,price,adjust_price,sku  ->  adjust_price 变成2位小数
        listing_id_list_map = list(
            map(lambda x: (x[0], x[1], x[2].quantize(decimal.Decimal('0.01')), x[3]), listing_id_list_map))
        # 价格区间
        if self.price_adjust_type == 1:
            # 过滤数据
            filter_listing_id_list = list(
                filter(lambda x: (x[1] * self.min_price / 100) <= x[2] <= (x[1] * self.max_price / 100),
                       listing_id_list_map))
        # 利润区间
        elif self.price_adjust_type == 2:
            sku_GrossProfitMargin_map = self.getCalculationGrossProfitMarginViewModelList(
                self.calculator_formula_id, self.source_id, listing_id_list_map)
            listing_id_list_map = list(
                map(lambda x: (
                    x[0], x[1], x[2], sku_GrossProfitMargin_map.get(x[3] + "@" + '{:.2f}'.format(x[2])), x[3]),
                    listing_id_list_map))

            # 过滤掉利润率负数
            def negative(listing_id_list_map):
                a = listing_id_list_map[3]
                return not float(a) < 0.00

            filter_listing_id_list = list(filter(negative, listing_id_list_map))
            filter_listing_id_list = list(
                filter(lambda x: self.min_profit <= Decimal(x[3]) <= self.max_profit,
                       filter_listing_id_list))
        return filter_listing_id_list

    def handlerCalculatorFormulas(self, listing_id_list):
        """
        调价方案： 计算器公式
        根据计算器公式，得到调整后的价格  验证是否在  原始价格*self.min_price ——  原始价格*self.max_price之间
        :param listing_id_list:
        :return:
        """
        # map数据
        listing_id_list_map = list(
            map(lambda x: (x[0], x[1], self.get_price(self.calculator_formula_id, self.source_id, x[2]), x[2]),
                listing_id_list))
        # 过滤数据
        filter_listing_id_list = list(
            filter(lambda x: (x[1] * self.min_price / 100) <= x[2] <= (x[1] * self.max_price / 100),
                   listing_id_list_map))
        return filter_listing_id_list


    def filter_queue(self,strategy_type,offer_id_set):
        if strategy_type == 1:
            filter_sql = f"""
            
            """


if __name__ == '__main__':
    # 9046
    # 9058
    # 9059
    # 9062

    # ExecuteStrategy(105, 9046).execute_strategy()
    ExecuteStrategy(112, 9046).get_negative_sku()
    # ExecuteStrategy(1,9058).check_actual_offer_id_set()
